%module windbg

%include <windows.i>
%include <typemaps.i>

%{
#undef send
#include "stdafx.h"
#include "../common/ByteArray.h"
#include "../common/WindbgExt.h"

void FlushIo();

#ifndef __FUNCTION__
#define __FUNCTION__ "<unknown>"
#endif

%}

%include "../common/swig/declarations.i"

// parameter typemaps
%{
	template<typename T>
	int ByteArrayRef(SWIG_MAYBE_PERL_OBJECT SV *sv, PVOID& ptr, ULONG& bufSize)
	{
		void *byteArray;
		int res = SWIG_ConvertPtr(sv, &byteArray, SWIGTYPE_p_ByteArray, 0 | 0);
		if (!SWIG_IsOK(res))
			return res;
		if (byteArray != NULL)
		{
			ptr = reinterpret_cast<ByteArray*>(byteArray)->GetBuffer();
			bufSize = reinterpret_cast<ByteArray*>(byteArray)->Size() / sizeof(T);
		}
		else
		{
			ptr = NULL;
			bufSize = 0;
		}
		return 0;
	}
%}

// out typemaps to report interface absence
%typemap(out) const NoThrowException*
{
	if ($1 != NULL)
		SWIG_croak($1->what);
	$result = SWIG_NewPointerObj(SWIG_as_voidptr(NULL), SWIGTYPE_p_NoThrowException, 0 | 0);
	++argvi;
}

%typemap(out) void*
{
	if ($1 == NULL)
		SWIG_croak("No interface");
	$result = SWIG_NewPointerObj(SWIG_as_voidptr($1), SWIGTYPE_p_long, 0 | 0);
	++argvi;
}

%typemap(out) IDebugAdvanced3*
{
	if ($1 == NULL)
		SWIG_croak("No interface");
	$result = SWIG_NewPointerObj(SWIG_as_voidptr($1), SWIGTYPE_p_IDebugAdvanced3, 0 | SWIG_SHADOW);
	++argvi;
}

%typemap(out) IDebugClient7*
{
	if ($1 == NULL)
		SWIG_croak("No interface");
	$result = SWIG_NewPointerObj(SWIG_as_voidptr($1), SWIGTYPE_p_IDebugClient7, 0 | SWIG_SHADOW);
	++argvi;
}

%typemap(out) IDebugControl7*
{
	if ($1 == NULL)
		SWIG_croak("No interface");
	$result = SWIG_NewPointerObj(SWIG_as_voidptr($1), SWIGTYPE_p_IDebugControl7, 0 | SWIG_SHADOW);
	++argvi;
}

%typemap(out) IDebugDataSpaces4*
{
	if ($1 == NULL)
		SWIG_croak("No interface");
	$result = SWIG_NewPointerObj(SWIG_as_voidptr($1), SWIGTYPE_p_IDebugDataSpaces4, 0 | SWIG_SHADOW);
	++argvi;
}

%typemap(out) IDebugRegisters2*
{
	if ($1 == NULL)
		SWIG_croak("No interface");
	$result = SWIG_NewPointerObj(SWIG_as_voidptr($1), SWIGTYPE_p_IDebugRegisters2, 0 | SWIG_SHADOW);
	++argvi;
}

%typemap(out) IDebugSymbols5*
{
	if ($1 == NULL)
		SWIG_croak("No interface");
	$result = SWIG_NewPointerObj(SWIG_as_voidptr($1), SWIGTYPE_p_IDebugSymbols5, 0 | SWIG_SHADOW);
	++argvi;
}

%typemap(out) IDebugSystemObjects4*
{
	if ($1 == NULL)
		SWIG_croak("No interface");
	$result = SWIG_NewPointerObj(SWIG_as_voidptr($1), SWIGTYPE_p_IDebugSystemObjects4, 0 | SWIG_SHADOW);
	++argvi;
}

// 64-bit integer references
%typemap(in) unsigned long long *REFERENCE (unsigned long long dvalue), unsigned long long &REFERENCE(unsigned long long dvalue),
			 unsigned __int64 *REFERENCE (unsigned __int64 dvalue), unsigned __int64 &REFERENCE(unsigned __int64 dvalue)
{
	SV *tempsv;
	if (!SvROK($input))
	{
		SWIG_croak("expected a reference");
	}
	tempsv = SvRV($input);
	if (!SvIOK(tempsv))
	{
		SWIG_croak("expected an integer reference");
	}
	dvalue = (unsigned long long) SvUV(tempsv);
	$1 = &dvalue;
} 

%typemap(typecheck) unsigned long long *REFERENCE, unsigned long long &REFERENCE,
					unsigned __int64 *REFERENCE, unsigned __int64 &REFERENCE
{
	$1 = SvROK($input);
	if($1)
	{
		SV *tmpsv = SvRV($input);
		$1 = SvUOK(tmpsv) || SvIOK(tmpsv);
	}
}

%typemap(argout) unsigned long long *REFERENCE, unsigned long long &REFERENCE,
				 unsigned __int64 *REFERENCE, unsigned __int64 &REFERENCE
{
	SV *tempsv;
	tempsv = SvRV($input);
	if (!$1) SWIG_croak("expected a reference");
	sv_setuv(tempsv, (UV) *$1);
} 

%typemap(in) (void* ptr, unsigned long size)
{
	int resByteArray = ByteArrayRef<BYTE>($input, $1, $2);
	if (!SWIG_IsOK(resByteArray))
		SWIG_exception_fail(SWIG_ArgError(resByteArray), "in method '" __FUNCTION__ "', argument $argnum of type '" "ByteArray *""'"); 
}

%typemap(in) (unsigned long* ptr, unsigned long size)
{
	int resByteArray = ByteArrayRef<ULONG>($input, *(reinterpret_cast<PVOID*>(&$1)), $2);
	if (!SWIG_IsOK(resByteArray))
		SWIG_exception_fail(SWIG_ArgError(resByteArray), "in method '" __FUNCTION__ "', argument $argnum of type '" "ByteArray *""'"); 
}

%typemap(in) (unsigned long size, unsigned long* ptr)
{
	int resByteArray = ByteArrayRef<ULONG>($input, *(reinterpret_cast<PVOID*>(&$2)), $1);
	if (!SWIG_IsOK(resByteArray))
		SWIG_exception_fail(SWIG_ArgError(resByteArray), "in method '" __FUNCTION__ "', argument $argnum of type '" "ByteArray *""'"); 
}

%typemap(in) (DEBUG_STACK_FRAME* ptr, unsigned long size)
{
	int resByteArray = ByteArrayRef<DEBUG_STACK_FRAME>($input, *(reinterpret_cast<PVOID*>(&$1)), $2);
	if (!SWIG_IsOK(resByteArray))
		SWIG_exception_fail(SWIG_ArgError(resByteArray), "in method '" __FUNCTION__ "', argument $argnum of type '" "ByteArray *""'"); 
}

%typemap(in) (PVOID Context, ULONG ContextSize) = (void* ptr, unsigned long size);
%typemap(in) (PVOID InBuffer, ULONG InBufferSize) = (void* ptr, unsigned long size);
%typemap(in) (PVOID OutBuffer, ULONG OutBufferSize) = (void* ptr, unsigned long size);
%typemap(in) (PVOID OptionsBuffer, ULONG OptionsBufferSize) = (void* ptr, unsigned long size);

%typemap(in) (ULONG Count, PULONG Types) = (unsigned long size, unsigned long* ptr);

%typemap(in) (PDEBUG_STACK_FRAME Frames, ULONG FramesSize) = (DEBUG_STACK_FRAME* ptr, unsigned long size);

// special for IDebugControl::OutputDisassemblyLines()
%typemap(in) (PULONG64 LineOffsets)
{
	ULONG bufSize;
	int resByteArray = ByteArrayRef<ULONG64>($input, *(reinterpret_cast<PVOID*>(&$1)), bufSize);
	if (!SWIG_IsOK(resByteArray))
		SWIG_exception_fail(SWIG_ArgError(resByteArray), "in method '" __FUNCTION__ "', argument $argnum of type '" "ByteArray *""'"); 
	if (($1 != NULL) && (bufSize < arg4))
		SWIG_croak("IDebugControl_OutputDisassemblyLines invalid argument: LineOffsets have to be large enough to hold TotalLines * sizeof(ULONG64) bytes");
}

%typemap(in) PDEBUG_BREAKPOINT Bp
{
	void *pobj;
    int res = SWIG_ConvertPtr($input, &pobj, SWIGTYPE_p_IDebugBreakpoint3, 0 | SWIG_POINTER_DISOWN);
    if (!SWIG_IsOK(res))
	{
		SWIG_exception_fail(SWIG_ArgError(res), "in method '" __FUNCTION__ "', argument $argnum of type '" "PDEBUG_BREAKPOINT""'"); 
    }
    $1 = reinterpret_cast<PDEBUG_BREAKPOINT>(pobj);
}

%typemap(in, numinputs=0) PDEBUG_BREAKPOINT *Bp (PDEBUG_BREAKPOINT temp)
{
	temp = NULL;
	$1 = &temp;
}

%typemap(argout) PDEBUG_BREAKPOINT *Bp
{
	$result = SWIG_NewPointerObj(SWIG_as_voidptr(*$1), SWIGTYPE_p_IDebugBreakpoint3, 0 | ((*$1 == NULL) ? 0 : SWIG_OWNER) | SWIG_SHADOW);
	argvi++;
}

%typemap(in, numinputs=0) PDEBUG_BREAKPOINT3 *Bp (PDEBUG_BREAKPOINT3 temp)
{
	temp = NULL;
	$1 = &temp;
}

%typemap(argout) PDEBUG_BREAKPOINT3 *Bp
{
    $result = SWIG_NewPointerObj(SWIG_as_voidptr(*$1), SWIGTYPE_p_IDebugBreakpoint3, 0 | ((*$1 == NULL) ? 0 : SWIG_OWNER) | SWIG_SHADOW);
	argvi++;
}

%typemap(in) PDEBUG_SYMBOL_GROUP Update
{
	void *pobj;
    int res = SWIG_ConvertPtr($input, &pobj, SWIGTYPE_p_IDebugSymbolGroup2, 0 | SWIG_POINTER_DISOWN);
    if (!SWIG_IsOK(res))
	{
		SWIG_exception_fail(SWIG_ArgError(res), "in method '" __FUNCTION__ "', argument $argnum of type '" "PDEBUG_SYMBOL_GROUP""'"); 
    }
    $1 = reinterpret_cast<PDEBUG_SYMBOL_GROUP>(pobj);
}

%typemap(in, numinputs=0) PDEBUG_SYMBOL_GROUP* Symbols (PDEBUG_SYMBOL_GROUP temp)
{
	temp = NULL;
	$1 = &temp;
}

%typemap(argout) PDEBUG_SYMBOL_GROUP* Symbols
{
    $result = SWIG_NewPointerObj(SWIG_as_voidptr(*$1), SWIGTYPE_p_IDebugSymbolGroup2, 0 | ((*$1 == NULL) ? 0 : SWIG_OWNER) | SWIG_SHADOW);
	argvi++;
}

%typemap(in) PDEBUG_SYMBOL_GROUP2 Update
{
	void *pobj;
    int res = SWIG_ConvertPtr($input, &pobj, SWIGTYPE_p_IDebugSymbolGroup2, 0 | SWIG_POINTER_DISOWN);
    if (!SWIG_IsOK(res))
	{
		SWIG_exception_fail(SWIG_ArgError(res), "in method '" __FUNCTION__ "', argument $argnum of type '" "PDEBUG_SYMBOL_GROUP2""'"); 
    }
    $1 = reinterpret_cast<PDEBUG_SYMBOL_GROUP2>(pobj);
}

%typemap(in, numinputs=0) PDEBUG_SYMBOL_GROUP2* Symbols (PDEBUG_SYMBOL_GROUP2 temp)
{
	temp = NULL;
	$1 = &temp;
}

%typemap(argout) PDEBUG_SYMBOL_GROUP2* Symbols
{
    $result = SWIG_NewPointerObj(SWIG_as_voidptr(*$1), SWIGTYPE_p_IDebugSymbolGroup2, 0 | ((*$1 == NULL) ? 0 : SWIG_OWNER) | SWIG_SHADOW);
	argvi++;
}

%apply PDEBUG_SYMBOL_GROUP* Symbols {PDEBUG_SYMBOL_GROUP* Group};
%apply PDEBUG_SYMBOL_GROUP2* Symbols {PDEBUG_SYMBOL_GROUP2* Group};

%apply ULONG64 *REFERENCE {PULONG64 EndOffset, PULONG64 Offset, PULONG64 StartOffset, PULONG64 EndOffset, PULONG64 NearOffset, PULONG64 Handle,
	PULONG64 Arg1, PULONG64 Arg2, PULONG64 Arg3, PULONG64 Arg4, PULONG64 MatchOffset, PULONG64 Value, PULONG64 Physical, PULONG64 NextOffset,
	PULONG64 ValidBase, PULONG64 TypeModule, PULONG64 Displacement, PULONG64 Base, PULONG64 Module, PULONG64 InstructionOffset, PULONG64 Server};


%include "../common/swig/dbgeng.i"

%include "../common/swig/windbgext.i"
